--[[
	GMod Last Man Standing, a gamemode for Garry's Mod
    Copyright (C) 2012 Wickex

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
]]

local function SetTeam()
	if GetConVar("glms_debug"):GetInt() == 1 then return TEAM_SURVIVALIST end
	if GetRoundState() == ROUND_GRACE then
		return TEAM_SURVIVALIST
	else
		return TEAM_SPEC
	end
end

function GM:PlayerInitialSpawn(ply)
	ply:SetTeam(SetTeam())
	
	ply:SetWalkSpeed(250)
	ply:SetRunSpeed(250)
	ply:SetJumpPower(160)
	ply:SetCrouchedWalkSpeed(0.3)
	ply:SetCanZoom(false)
end

function GM:PlayerSpawn(ply)
	self.BaseClass:PlayerSpawn(ply)
	
	SendRoundState(GetRoundState(), ply)
	
	if ply:IsSpec() then
		ply:StripAll()
		ply:Spectate(OBS_MODE_ROAMING)
		return
	end
	
	ply:UnSpectate()
	
	ply:SetHealth(100)
	ply:SetHunger(100)
end

function GM:PlayerLoadout(ply)
	if ply:Team() == TEAM_SURVIVALIST then
		ply:Give("weapon_glms_fists")
		ply:Give("weapon_glms_shovel")
	end
end

function GM:PlayerDeath(ply, inflictor, attacker)
	self:PlayerSilentDeath(ply)
	
	ply:SetTeam(TEAM_SPEC)
	ply:Freeze(false)
	ply:Spectate(OBS_MODE_ROAMING)

	ply:Flashlight(false)

	ply:Extinguish()
end

function GM:CanPlayerSuicide(ply)
	return ply:IsSurvivalist()
end

function GM:PlayerSwitchFlashlight(ply, state)
	if not IsValid(ply) then return false end
	if (not state) or ply:IsTerror() then
		if state then
			ply:AddEffects(EF_DIMLIGHT)
		else
			ply:RemoveEffects(EF_DIMLIGHT)
		end
	end
	return false
end

function GM:KeyPress(ply, key)
	if not IsValid(ply) then return end
	
	if ply:IsSpec() then
		
		if key == IN_ATTACK then
			ply:Spectate(OBS_MODE_ROAMING)
			ply:SpectateEntity(nil)
			
			local alive = GetAlivePlayers()
			
			if #alive < 1 then return end
			
			local target = table.Random(alive)
			if IsValid(target) then
				ply:SetPos(target:EyePos())
			end
		elseif key == IN_ATTACK2 then
			local target = GetNextAlivePlayer(ply:GetObserverTarget())
			
			if IsValid(target) then
				ply:Spectate(ply.spec_mode or OBS_MODE_CHASE)
				ply:SpectateEntity(target)
			end
		elseif key == IN_DUCK then
			local pos = ply:GetPos()
			local ang = ply:EyeAngles()
			
			local target = ply:GetObserverTarget()
			if IsValid(target) and target:IsPlayer() then
				pos = target:EyePos()
				ang = target:EyeAngles()
			end
			
			ply:Spectate(OBS_MODE_ROAMING)
			ply:SpectateEntity(nil)
			
			ply:SetPos(pos)
			ply:SetEyeAngles(ang)
			return true
		elseif key == IN_JUMP then
			if not (ply:GetMoveType() == MOVETYPE_NOCLIP) then
				ply:SetMoveType(MOVETYPE_NOCLIP)
			end
		elseif key == IN_RELOAD then
			local tgt = ply:GetObserverTarget()
			if not IsValid(tgt) or not tgt:IsPlayer() then return end
			
			if not ply.spec_mode or ply.spec_mode == OBS_MODE_CHASE then
				ply.spec_mode = OBS_MODE_IN_EYE
			elseif ply.spec_mode == OBS_MODE_IN_EYE then
				ply.spec_mode = OBS_MODE_CHASE
			end
			
			ply:Spectate(ply.spec_mode)
		end
	end
end

--Thank you TTT!

function GM:SpectatorThink(ply)
	if ply:GetMoveType() < MOVETYPE_NOCLIP and ply:GetMoveType() > 0 or ply:GetMoveType() == MOVETYPE_LADDER then
		ply:Spectate(OBS_MODE_ROAMING)
	end
	
	if ply:GetObserverMode() != OBS_MODE_ROAMING then
		local target = ply:GetObserverTarget()
		if IsValid(target) and tgt:IsPlayer() then
			if (not target:IsSurvivalist()) or (not target:Alive()) then
				ply:Spectate(OBS_MODE_ROAMING)
				ply:SpectateEntity(nil)
			elseif (GetRound() == ROUND_GRACE) or (GetRound() == ROUND_START) then
				ply:SetPos(target:GetPos())
			end
		end
	end
end

GM.PlayerDeathThink = GM.SpectatorThink

function GM:ScalePlayerDamage(ply, hitgroup, dmginfo)
	dmginfo:SetDamage(dmginfo:GetBaseDamage() / 2)
	--dmginfo:ScaleDamage(0.5) --Scaling dmg later, not sure if that'll conflict? Going the safer route
	
	ply.was_headshot = false
	
	if hitgroup == HITGROUP_HEAD then
		ply.was_headshot = dmginfo:IsBulletDamage()
		
		local wep = WeaponFromDamage(dmginfo)
		
		if IsValid(wep) then
			if wep:IsRanged() then
				local scale = wep:GetHeadshotMultiplier(ply, dmginfo) or 2
				dmginfo:ScaleDamage(scale)
			elseif wep:IsMelee() then
				local scale = wep:GetHeadshotMultiplier(ply, dmginfo) or 1.5
				dmginfo:ScaleDamage(scale)
			elseif wep:IsHands() then
				local scale = wep:GetHeadshotMultiplier(ply, dmginfo) or 1.25
				dmginfo:ScaleDamage(scale)
			end
		end
	elseif (hitgroup == HITGROUP_LEFTARM or
			hitgroup == HITGROUP_RIGHTARM or
			hitgroup == HITGROUP_LEFTLEG or
			hitgroup == HITGROUP_RIGHTLEG or
			hitgroup == HITGROUP_GEAR ) then

		if wep:IsRanged() then
			dmginfo:ScaleDamage(0.5)
		elseif wep:IsMelee() or wep:IsHands() then
			dmginfo:ScaleDamage(0.85)
		end
   end
   
   if (dmginfo:IsDamageType(DMG_DIRECT) or
       dmginfo:IsExplosionDamage() or
       dmginfo:IsDamageType(DMG_FALL) or
       dmginfo:IsDamageType(DMG_PHYSGUN)) then
		dmginfo:ScaleDamage(2)
	end
end

function GM:GetFallDamage(ply, speed)
	return 1
end

local fallsounds = {
	Sound("player/damage1.wav"),
	Sound("player/damage2.wav"),
	Sound("player/damage3.wav")
};

function GM:OnPlayerHitGround(ply, in_water, on_floater, speed)
	if in_water or speed < 450 or not IsValid(ply) then return end
	local damage = math.pow(0.05 * (speed - 420), 1.75)
	if on_floater then damage = damage / 2 end
	
	local ground = ply:GetGroundEntity()
	if IsValid(ground) and ground:IsPlayer() then --Goomba, thanks TTT
		if math.floor(damage) > 0 then
			local att = ply

			local dmg = DamageInfo()

			dmg:SetDamageType(DMG_CRUSH + DMG_PHYSGUN)

			dmg:SetAttacker(att)
			dmg:SetInflictor(att)
			dmg:SetDamageForce(Vector(0,0,-1))
			dmg:SetDamage(damage)

			ground:TakeDamageInfo(dmg)
		end

		damage = damage / 3
	end
	
	if math.floor(damage) > 0 then
		local dmg = DamageInfo()
		dmg:SetDamageType(DMG_FALL)
		dmg:SetAttacker(game.GetWorld())
		dmg:SetInflictor(game.GetWorld())
		dmg:SetDamageForce(Vector(0,0,1))
		dmg:SetDamage(damage)

		ply:TakeDamageInfo(dmg)
		
		if damage > 5 then
			sound.Play(table.Random(fallsounds), ply:GetShootPos(), 55 + math.Clamp(damage, 0, 50), 100)
		end
	end
end

--function GM:EntityTakeDamage(ent, infl, att, amount, dmginfo)
function GM:EntityTakeDamage(target, dmginfo)
	if not IsValid(target) then return end
	
	if GetRoundState() == ROUND_GRACE and target:IsPlayer() then
		dmginfo:ScaleDamage(0.5)
	end
end